import { Bi, Ei, Pi } from "@/module-00-codebase/pkg-01-container";
export type InitsParam = {
  name: string;
  clazz: new () => any;
  others?: { initializing?: (behavior: any) => Promise<void>; dependencies?: () => string[]; order?: () => number };
  initing?: boolean;
  inited?: boolean;
};

// initBehaviors, initComponents, initPages
export const initBehaviors = async (inits: InitsParam[]) => {
  const map = inits.sort(behaviorSorter).reduce((map, o) => map.set(o.name, o), new Map<string, InitsParam>());
  for (let key of Array.from(map.keys())) await initBehavior(map.get(key), map);
};
export const initComponents = (inits: InitsParam[]) => inits.forEach(initComponent);
export const initPages = (inits: InitsParam[]) => inits.forEach(initPage);

// createBehaviorInitsParam for initBehaviors
export const createBehaviorInitsParam = (dyModule: any, key: string, className: string) => {
  const { initializing, dependencies, order } = dyModule;
  return { name: key, clazz: dyModule[className], others: { initializing, dependencies, order } };
};

// initBehavior, initComponent, initPage
const initBehavior = async (init: InitsParam | undefined, map: Map<string, InitsParam>) => {
  if (!init) {
    throw new Error(`Impossible Error: InitsParam is ${init}.`);
  } else if (!!init.inited) {
    // skip
  } else if (!!init.initing) {
    throw new Error(`Cycle Reference: Behavior ${init.name}`);
  } else {
    init.initing = true;
    const behavior = new init.clazz();
    if (!!init?.others?.dependencies) {
      for (let key of init.others.dependencies.call(null)) {
        await initBehavior(map.get(key), map);
      }
    }
    if (!!init?.others?.initializing) {
      await init.others.initializing.call(null, behavior);
    }
    init.inited = true;
    init.initing = false;
    (Bi as any)[`${init.name[0].toLowerCase()}${init.name.substring(1)}`] = behavior;
  }
};
const initComponent = (init: InitsParam) => ((Ei as any)[init.name] = init.clazz);
const initPage = (init: InitsParam) => {
  // 1. 该方案性能和容错更高，但开发环境热重载会导致 clazz.pageRoutePath 被抹除
  //   const pageRouteFunc = (path => () => path)(init.name || "/");
  //   init.clazz.prototype.pageRoutePath = pageRouteFunc;
  //   (Pi as any)[pageRouteFunc()] = init.clazz;
  // 2. 故采用继承法方案，不改变原有类，创建新类
  const path = init.name || "/";
  (Pi as any)[path] = class AnyPage extends init.clazz {
    pageRoutePath() {
      return path;
    }
  };
};
// initBehaviors <- behaviorSorter
const behaviorSorter = (a: InitsParam, b: InitsParam) => {
  const sorta = a.others?.order?.call(null) || 0;
  const sortb = b.others?.order?.call(null) || 0;
  if (sorta === sortb) {
    return 0;
  } else if (sorta < sortb) {
    return -1;
  } else {
    return 1;
  }
};
